﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using ZQNB.Common;

namespace ZQNB.Entity.Rbac2
{
    //站点路由唯一名改名！
    //删除组织节点site1
    //移动组织节点从site1 => site2
    //删除用户
    //移动用户 从org1 => org2

    //root Role定制的时候是否应该影响到孩子？

    #region context
    public class RbacContext
    {
        public SiteContext Site { get; set; }
        public UserContext User { get; set; }
        public IList<RoleContext> Roles { get; set; }
        public OpContext Op { get; set; }
        public ObjContext Obj { get; set; }
    }
    public class SiteContext
    {
        public string Name { get; set; }
        public string Description { get; set; }
    }
    public class RoleContext
    {
        public string Site { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
    }
    public class UserContext
    {
        public string Site { get; set; }
        public string LoginName { get; set; }
        public string FullName { get; set; }
    }
    public class OpContext
    {
        public string Pk { get; set; }
    }
    public class ObjContext
    {
        public string Pk { get; set; }
        public ObjType ObjType { get; set; }
    }
    #endregion

    public interface ISiteObj
    {
        string Site { get; set; }
    }
    public interface IRbacRule
    {
        bool CheckRule(RbacContext rbacContext);
    }

    public abstract class RbacEntity
    {
        public virtual Guid Id { get; set; }
    }

    public class Role : RbacEntity, ISiteObj
    {
        public string Site { get; set; }
        public string Code { get; set; }
        //public string Name { get; set; }
    }

    public class User : RbacEntity
    {
        public string LoginName { get; set; }
    }

    public enum OpType
    {
        SubjectOp = 0,
        ObjectOp = 1
    }

    public class Op : RbacEntity
    {
        public string Pk { get; set; }
        public OpType OpType { get; set; }
        /// <summary>
        /// 是否仅站内可见
        /// </summary>
        public bool InnerSite { get; set; }

    }

    public enum ObjType
    {
        Resource = 0,
        ResourceDirectory = 1,
        ResourceSubject = 2,
        Live = 3,
        Site = 4
    }

    public class Obj : RbacEntity
    {
        public string Pk { get; set; }
        public ObjType ObjType { get; set; }
    }

    public class UserRole : RbacEntity, ISiteObj
    {
        public string Site { get; set; }
        public Role Role { get; set; }
        public User User { get; set; }
    }

    //op为客体操作Obj才会有值
    public class UserRule : RbacEntity, ISiteObj, IRbacRule
    {
        public string Site { get; set; }
        public User User { get; set; }
        public Op Op { get; set; }
        public Obj Obj { get; set; }

        public bool CheckRule(RbacContext rbacContext)
        {
            if (rbacContext == null)
            {
                throw new ArgumentNullException("rbacContext");
            }

            //不是同一个op，直接返回false
            if (!rbacContext.Op.Pk.NbEquals(this.Op.Pk))
            {
                return false;
            }

            //如果是客体权限，还应该验证Obj
            if (this.Op.OpType == OpType.ObjectOp)
            {
                if (!rbacContext.Obj.Pk.NbEquals(this.Op.Pk))
                {
                    return false;
                }
            }

            //不是同一个user，直接返回false
            if (!rbacContext.User.LoginName.NbEquals(this.User.LoginName))
            {
                return false;
            }

            //如果不是全局设置，还应该进一步验证site
            if (!string.IsNullOrWhiteSpace(this.Site) && !this.Site.NbEquals(rbacContext.Site.Name))
            {
                return false;
            }

            return true;
        }
    }

    //op为客体操作Obj才会有值
    public class RoleRule : RbacEntity, ISiteObj, IRbacRule
    {
        public string Site { get; set; }
        public Role Role { get; set; }
        public Op Op { get; set; }
        public Obj Obj { get; set; }

        public bool CheckRule(RbacContext rbacContext)
        {
            if (rbacContext == null)
            {
                throw new ArgumentNullException("rbacContext");
            }

            //不是同一个op，直接返回false
            if (!rbacContext.Op.Pk.NbEquals(this.Op.Pk))
            {
                return false;
            }

            //如果是客体权限，还应该验证Obj
            if (this.Op.OpType == OpType.ObjectOp)
            {
                if (!rbacContext.Obj.Pk.NbEquals(this.Op.Pk))
                {
                    return false;
                }
            }


            //不包含这个role，直接返回false
            var theRole = rbacContext.Roles.FirstOrDefault(x => x.Code.NbEquals(this.Role.Code) && x.Site.NbEquals(this.Role.Site));
            if (theRole == null)
            {
                return false;
            }

            //如果不是全局设置，还应该进一步验证site
            if (!string.IsNullOrWhiteSpace(this.Site) && !this.Site.NbEquals(rbacContext.Site.Name))
            {
                return false;
            }

            return true;
        }
    }


    public interface IRbacRuleService
    {
        //subject视角
        IList<UserRule> GetUserRules(string site, string userLoginName);
        IList<RoleRule> GetRoleRules(string site, string roleSite, string roleCode);

        //object视角
        IList<UserRule> GetUserRulesForObj(string site, string objPk);
        IList<RoleRule> GetRoleRulesForObj(string site, string objPk);

        //0 get opType(sub or obj) && getSite
        //1 get userRules => where x.op == op => userRulesForOp => check
        //2 get roleRules => where x.op == op => roleRulesForOp => check
        //3 return result!
        bool CheckRule(RbacContext requestContext);
    }
}
